#pragma once
#include<iostream>
#include<vector>
#include<cassert>
#include <algorithm>
//using namespace std;
#define BUFFER_SIZE 4096
class Buffer {
public:
    Buffer() :_capacity(BUFFER_SIZE), _data(_capacity),
        _read_start(0), _write_start(0), _size(0) {
    }
    //返回剩余空间的大小
    size_t GetFreeSpace() {
        return _capacity - _size;
    }
    //返回已用空间的大小
    size_t GetSize() {
        return _size;
    }
    //返回缓冲区读取起始的位置
    size_t GetReadStart() {
        return _read_start;
    }
    //返回缓冲区写入起始的位置
    size_t GetWriteStart() {
        return _write_start;
    }
    //移动读取起始位置
    void MoveReadStart(const size_t len) {
        if (len > _size) {
            assert(0);
        }
        _read_start += len; _size -= len;
        if (_read_start < 0) {
            _read_start += _capacity;
        }
    }
    //移动写入起始位置
    void MoveWriteStart(const size_t len) {
        if (_size + len > _capacity) {
            assert(0);
        }
        _write_start += len; _size += len;
        if (_write_start >= _capacity) {
            _write_start %= _capacity;
        }
    }
    //读取数据但不删除数据
    std::string Read(size_t size = -1) {
        // std::cout<<"Read:"<<_size<<std::endl;
        if (_size == 0) {
            return "";
        }
        std::string str;
        int bg = _read_start;
        for (int i = 0; i < std::min(size, _size); i++) {
            str.push_back(_data[bg++]);
            if (bg == _capacity) {
                bg = 0;
            }
        }
        return str;
    }
    //读取并删除数据,如果读取的数据超过缓冲区已有数据大小，返回全部数据
    std::string ReadAndPop(size_t size = -1) {
        std::string str = Read(size);
        MoveReadStart(str.size());
        // std::cout<<"ReadAndPop:"<<str.size()<<std::endl;
        //_size-=str.size();
        // std::cout<<"ReadAndPop:"<<_size<<std::endl;
        return str;
    }
    //扩容，这个扩容只扩容到刚好能容纳所有数据
    bool CapacityExpansion(const size_t size) {
        // std::cout<<"CapacityExpansion:"<<_capacity<<std::endl;
        // std::cout<<"CapacityExpansion:"<<_size<<std::endl;
        // std::cout<<"_write_start:"<<_write_start<<std::endl;
        // std::cout<<"_read_start:"<<_read_start<<std::endl;
        std::vector<char> new_data(size);
        std::string str = Read();
        if (str == "") {
            //std::cout<<"CapacityExpansion:no need expansion"<<std::endl;
            return true;
        }
        if (size < str.size()) {
            assert(0);
        }
        for (int i = 0; i < str.size(); i++) {
            new_data[i] = str[i];
        }
        std::swap(new_data, _data);
        _write_start = _size;
        _capacity = size; _read_start = 0;
        return true;
    }
    //向缓冲区写入数据
    bool Write(const std::string str) {
        //std::cout<<"Write:"<<str.size()<<std::endl;
        if (_size + str.size() > _capacity) {
            if (CapacityExpansion(_capacity + str.size())) {
                for (int i = 0; i < str.size(); i++) {
                    _data[_write_start++] = str[i];
                    if (_write_start == _capacity) {
                        _write_start = 0;
                    }
                }
            }
            else {
                return false;
            }
        }
        else {
            for (int i = 0; i < str.size(); i++) {
                _data[_write_start++] = str[i];
                if (_write_start == _capacity) {
                    _write_start = 0;
                }
            }
        }
        //std::cout<<"Write:"<<_size<<std::endl;
        _size += str.size();
        return true;
    }
    bool Write(const char* str) {
        return Write(std::string(str));
    }
    bool Write(Buffer& str) {
        std::string s = str.ReadAndPop();
        return Write(s);
    }
    int find() {
        for (int i = 0; i < _size; i++) {
            if (_data[_read_start + i] == '\n') {
                return _read_start + i;
            }
        }
        return -1;
    }
    std::string GetLine() {
        int pos = find();
        if (pos == -1) {
            return "";
        }
        std::string str;
        if (pos > _read_start) {
            str = Read((size_t)pos - _read_start + 1);
        }
        else {
            str = Read((size_t)pos + _capacity - _read_start + 1);
        }
        return str;
    }
    std::string GetLineAndPop() {
        std::string str = GetLine();
        MoveReadStart(str.size());
        return str;
    }
    void Clear() {
        _read_start = _write_start = _size = 0;
    }
private:
    size_t _read_start, _write_start;
    size_t _capacity, _size;
    std::vector<char> _data;
};